package naga.x.platform2.support;

import java.lang.reflect.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class EnumArrayTypeHandler<T extends Enum<T>> extends BaseTypeHandler<T[]> {
	
	private final Class<T> type;
	
	public EnumArrayTypeHandler(Class<T> type) {
		this.type = type;
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, T[] parameter, JdbcType jdbcType) throws SQLException {
		ps.setString(i, serialize(parameter));
	}

	@Override
	public T[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
		return deserialize(rs.getString(columnName));
	}

	@Override
	public T[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		return deserialize(rs.getString(columnIndex));
	}

	@Override
	public T[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		return deserialize(cs.getString(columnIndex));
	}
	
	private String serialize(T[] array) {
		int mask = disableEnumFeatures();
		String json = JSON.toJSONString(array);
		enableEnumFeatures(mask);
		return json;
	}
	
	private T[] deserialize(String json) {
		int mask = disableEnumFeatures();
		List<T> list = JSON.parseArray(json, type);
		if (list == null) {
			return null;
		}
		T[] arr = (T[]) Array.newInstance(type, list.size());
		list.toArray(arr);
		enableEnumFeatures(mask);
		return arr;
	}
	
	private static int disableEnumFeatures() {
		int mask = 0;
		int features = JSON.DEFAULT_GENERATE_FEATURE;
		SerializerFeature feature = SerializerFeature.WriteEnumUsingToString;
		if (SerializerFeature.isEnabled(features, feature)) {
			features = SerializerFeature.config(features, feature, false);
			mask |= feature.mask;
		}
		feature = SerializerFeature.WriteEnumUsingName;
		if (SerializerFeature.isEnabled(features, feature)) {
			features = SerializerFeature.config(features, feature, false);
			mask |= feature.mask;
		}
		JSON.DEFAULT_GENERATE_FEATURE = features;
		return mask;
	}
	
	private static void enableEnumFeatures(int mask) {
		int features = JSON.DEFAULT_GENERATE_FEATURE;
		SerializerFeature feature = SerializerFeature.WriteEnumUsingToString;
		if (SerializerFeature.isEnabled(mask, feature)) {
			features = SerializerFeature.config(features, feature, true);
		}
		feature = SerializerFeature.WriteEnumUsingName;
		if (SerializerFeature.isEnabled(mask, feature)) {
			features = SerializerFeature.config(features, feature, true);
		}
		JSON.DEFAULT_GENERATE_FEATURE = features;
	}

}
